// Code from Visualizing Data, First Edition, Copyright 2008 Ben Fry.
// Based on the GraphLayout example by Sun Microsystems.

int nodeCount;
static final color nodeColor   = #F0C070;
static final color selectColor = #FF3030;
static final color fixedColor  = #FF8080;
static final color edgeColor   = #000000;

Node[] nodes = new Node[100];
HashMap nodeTable = new HashMap();

int edgeCount;
Edge[] edges = new Edge[500];

PFont font;
String[] lines;

// arrays to hold top user and hash data
String[][] top_hash = new String[7][100];
String[][] top_users = new String[7][100];
String[] topString;

String[] currentGraphArray = { 
  "No Option Selected"
};
DropdownList graphList;

RadioButton r;

int graphValue;

// This string holds the help and description information
static final String graphInfo = "GRAPH: The graph display type\n"
             +"shows relationships between\n"
             +"@users->#hashtags or #hashtags\n-> "
             +"@users. The size of the nodes\n"
             +"correspond to the number of times\n"
             +"that relationship has been seen\nin a "
             +"tweet message.\n\n"
             +"TO GET STARTED: Select a month from\n"
             +"the drop down list, then select a\n"
             +"USER/HASHTAG from the drop down list";

// a boolean that keeps track of which radio button is selected
boolean usersSelected = false;

// data tables that will hold data for each file
Table[] userData;
Table[] hashData;

// these arrays will hold the index values of the user information
int[][] userIndexes = new int[7][100];
int[][] hashIndexes = new int[7][100];

void setupGraph() {  
  userData = new Table[7];
  hashData = new Table[7];
  loadData();
  println(edgeCount);
  font = createFont("SansSerif", 10);
  textFont(font);  
  smooth();
}

void drawGraph() {

  background(255);

  for (int i = 0 ; i < edgeCount ; i++) {
    edges[i].relax();
  }
  for (int i = 0; i < nodeCount; i++) {
    nodes[i].relax();
  }
  for (int i = 0; i < nodeCount; i++) {
    nodes[i].update();
  }
  for (int i = 0 ; i < edgeCount ; i++) {
    edges[i].draw();
  }
  for (int i = 0 ; i < nodeCount ; i++) {
    nodes[i].draw();
  }

  showDescriptionBox(graphInfo);
}

void usersChecked() {
  usersSelected = true;
  currentGraphArray = top_users[Cur_month - 6];
  updateGraphDLL();
}

void hashChecked() {
  usersSelected = false;
  currentGraphArray = top_hash[Cur_month - 6];
  updateGraphDLL();
}


void addToRadioButton(RadioButton theRadioButton, String theName, int theValue ) {
  Toggle t = theRadioButton.addItem(theName,theValue);
  t.captionLabel().setColorBackground(color(80));
  t.captionLabel().style().movePadding(2,0,-1,2);
  t.captionLabel().style().moveMargin(-2,0,0,-3);
  t.captionLabel().style().backgroundWidth = 46;
}

void setupRadioButton() {
  r = controlP5.addRadioButton("radioButton",controlX+240,controlY-15);
  r.setColorForeground(color(120));
  r.setColorActive(color(#FF0000));
  r.setColorLabel(color(255));
  r.setItemsPerRow(5);
  r.setSpacingColumn(50);

  addToRadioButton(r,"User",1);
  addToRadioButton(r,"Hashtag",2);

  r.hide();
}

void setupGraphDDL() {
  graphList = controlP5.addDropdownList("graphList",controlX+380,controlY,100,120);
  customize(graphList, "user/hash list", currentGraphArray);
  graphList.hide();
}

void updateGraphDLL() {
  graphList.clear();
  customize(graphList, "user/hash list", currentGraphArray);
}

void loadData() {
  // load files into corresponding data tables
  for (int i = 0; i < 7; i++) {
    userData[i] = new Table("user_hash_" + (i+6));
    hashData[i] = new Table("hash_user_" + (i+6));
  }

  String topTemp;
  // load the top user and hash data
  for (int i = 0; i < 7; i ++) {
    topString = loadStrings("top/top_hash_" + (i+6));
    topTemp = join(topString, "|");
    top_hash[i] = splitTokens(topTemp, "|");
    topString = loadStrings("top/top_users_" + (i+6));
    topTemp = join(topString, "|");
    top_users[i] = splitTokens(topTemp, "|");
  }

  // calculate indicies for each username
  for (int i=0; i < 7; i++) {
    for (int j=0; j<100; j++) {
      for (int k=0; k < hashData[i].getRowCount();k++) {
        if (top_hash[i][j].equals(hashData[i].getString(k,1))) {
          hashIndexes[i][j] = k;
          break;
        }
      }
    }
  }

  // calculate indicies for each username
  for (int i=0; i < 7; i++) {
    for (int j=0; j<100; j++) {
      //println(userData[i].getString(1,1));
      for (int k=0; k < userData[i].getRowCount();k++) {
        if (top_users[i][j].equals(userData[i].getString(k,1))) {
          userIndexes[i][j] = k;
          break;
        }
      }
    }
  }
/*
  lines = loadStrings("oxgirl.txt");

  // Make the text into a single String object
  String line = join(lines, "|");

  // Replace -- with an actual em dash
  //line = line.replaceAll("--", "\u2014");

  // Split into phrases using any of the provided tokens
  String[] phrases = splitTokens(line, "|");
  //println(phrases);

  for (int i = 0; i < phrases.length; i++) {
    // Make this phrase lowercase
    String phrase = phrases[i].toLowerCase();
    // Split each phrase into individual words at one or more spaces
    String[] words = splitTokens(phrase, "\t");
    for (int w = 0; w < words.length-1; w++) {
      addEdge(words[w], words[w+1], 50);
    }
  }
  */
}

void userClicked() {

  int maxData = int(userData[Cur_month-6].getString(userIndexes[Cur_month-6][graphValue],0));
  
  clearGraph();
  
  for (int i=0; i < 10; i++) {
    addEdge(top_users[Cur_month-6][graphValue], 
            userData[Cur_month-6].getString((userIndexes[Cur_month-6][graphValue] + i),2),
            (int)map(int(userData[Cur_month-6].getString((userIndexes[Cur_month-6][graphValue] + i),0)),0,maxData,50,200));
  }
}

void hashClicked() {
  int maxData = int(hashData[Cur_month-6].getString(hashIndexes[Cur_month-6][graphValue],0));
  
  clearGraph();
  
  for (int i=0; i < 10; i++) {
    addEdge(top_hash[Cur_month-6][graphValue], 
            hashData[Cur_month-6].getString((hashIndexes[Cur_month-6][graphValue] + i),2), 
            (int)map(int(hashData[Cur_month-6].getString((hashIndexes[Cur_month-6][graphValue] + i),0)), 0, maxData, 50, 200));
  }
}


void addEdge(String fromLabel, String toLabel, int count) {
  // Filter out unnecessary words
  if (ignoreWord(fromLabel) || ignoreWord(toLabel)) return;

  Node from = findNode(fromLabel);
  Node to = findNode(toLabel);
  to.setCount(count);

  for (int i = 0; i < edgeCount; i++) {
    if (edges[i].from == from && edges[i].to == to) {
      edges[i].increment();
      return;
    }
  } 

  Edge e = new Edge(from, to);
  e.increment();
  if (edgeCount == edges.length) {
    edges = (Edge[]) expand(edges);
  }
  edges[edgeCount++] = e;
}


String[] ignore = { 
  "a", "of", "the", "i", "it", "you", "and", "to"
};

boolean ignoreWord(String what) {
  for (int i = 0; i < ignore.length; i++) {
    if (what.equals(ignore[i])) {
      return true;
    }
  }
  return false;
}


Node findNode(String label) {
  label = label.toLowerCase();
  Node n = (Node) nodeTable.get(label);
  if (n == null) {
    return addNode(label);
  }
  return n;
}

void clearGraph() {
  for (int i=0; i < edgeCount;i++) {
    edges[i] = new Edge();
  }
  edgeCount = 0;
  for (int i=0; i < nodeCount;i++) {
    nodes[i] = new Node();
  }
  nodeCount = 0;
  nodeTable.clear();
}

Node addNode(String label) {
  Node n = new Node(label);  
  if (nodeCount == nodes.length) {
    nodes = (Node[]) expand(nodes);
  }
  nodeTable.put(label, n);
  nodes[nodeCount++] = n;  
  return n;
}

Node selection; 

void mousePressed() {
  // Ignore anything greater than this distance
  float closest = 20;
  for (int i = 0; i < nodeCount; i++) {
    Node n = nodes[i];
    float d = dist(mouseX, mouseY, n.x, n.y);
    if (d < closest) {
      selection = n;
      closest = d;
    }
  }
  if (selection != null) {
    if (mouseButton == LEFT) {
      selection.fixed = true;
    } 
    else if (mouseButton == RIGHT) {
      selection.fixed = false;
    }
  }
}


void mouseDragged() {
  if (selection != null) {
    selection.x = mouseX;
    selection.y = mouseY;
  }
}


void mouseReleased() {
  selection = null;
}

